package web

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"github.com/google/uuid"
	"github.com/redis/go-redis/v9"
	"strings"
	"time"
)

/*
* Author: JacksonCoder
* CreateTime: 2025/7/21
 */
type jwtHandler struct {
	// access_token key
	atKey []byte
	// refresh_token key
	rtKey []byte
}

type RedisJWTHandler struct {
	cmd redis.Cmdable
}

func newJwtHandler() jwtHandler {
	return jwtHandler{
		atKey: []byte("u8PTdRvjxVeKA5qk4XDChYTGVTUGf3hs"),
		rtKey: []byte("gfmfP73DqcAXt9m6qyFT5qtCecNcmHSy"),
	}
}

func (h jwtHandler) setLoginToken(ctx *gin.Context, uid int64) error {
	ssid := uuid.New().String()
	err := h.setJWTToken(ctx, uid, ssid)
	if err != nil {
		return err
	}
	err = h.setRefreshToken(ctx, uid, ssid)
	return err
}

func (h jwtHandler) setJWTToken(ctx *gin.Context, uid int64, Ssid string) error {
	// 在这里用 JWT 设置登录态
	// 生成一个 JWT TOKEN
	claims := UserClaims{
		RegisteredClaims: jwt.RegisteredClaims{
			// 设置过期时间
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute)),
		},
		Uid:       uid,
		Ssid:      Ssid,
		UserAgent: ctx.Request.UserAgent(),
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS512, claims)
	tokenStr, err := token.SignedString(h.atKey)
	if err != nil {
		return err
	}
	ctx.Header("x-jwt-token", tokenStr)
	return nil
}

func (h jwtHandler) setRefreshToken(ctx *gin.Context, uid int64, Ssid string) error {
	// 在这里用 JWT 设置登录态
	// 生成一个 JWT TOKEN
	claims := RefreshClaims{
		Ssid: Ssid,
		RegisteredClaims: jwt.RegisteredClaims{
			// 设置过期时间
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24 * 7)),
		},
		Uid: uid,
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS512, claims)
	tokenStr, err := token.SignedString(h.rtKey)
	if err != nil {
		return err
	}
	ctx.Header("x-refresh-token", tokenStr)
	return nil
}

func (h *RedisJWTHandler) CheckSession(ctx *gin.Context, ssid string) error {
	val, err := h.cmd.Exists(ctx, fmt.Sprintf("users:ssid:%s", ssid)).Result()
	switch err {
	case redis.Nil:
		return nil
	case nil:
		if val == 0 {
			return nil
		}
		return errors.New("session 已经无效了")
	default:
		return err
	}
}

func ExtractToken(ctx *gin.Context) string {
	// 我现在用 JWT 来校验
	tokenHeader := ctx.GetHeader("Authorization")
	// segs := strings.SplitN(tokenHeader , " ", 2)
	segs := strings.Split(tokenHeader, " ")
	if len(segs) != 2 {
		// 没登入， 有人瞎搞
		return ""
	}
	return segs[1]
}

type RefreshClaims struct {
	Uid  int64
	Ssid string
	jwt.RegisteredClaims
}

type UserClaims struct {
	// 核心是实现一个 claims
	jwt.RegisteredClaims
	// 声明自己要放进去 token 里面的数据
	Uid  int64
	Ssid string
	// 自己随便加 ...  注意：不要放入敏感信息
	UserAgent string
}
